package com.hyk.learning.circuitBreaker;

import lombok.Getter;
import org.checkerframework.checker.units.qual.A;
import org.omg.CORBA.PRIVATE_MEMBER;

import javax.xml.bind.annotation.XmlType;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @className: CircuitBreaker
 * @author: hyk199710
 * @description: 客户端熔断器
 * @date: 2024/9/6 0:29
 */
public class CircuitBreaker {
    //状态
    @Getter
    private CircuitBreakerState state = CircuitBreakerState.CLOSED;
    private AtomicInteger failureCount = new AtomicInteger(0);
    private AtomicInteger successCount = new AtomicInteger(0);
    private AtomicInteger requestCount = new AtomicInteger(0);
    //失败次数阈值
    private final int failureThreshold;
    //半开启次数/成功次数
    private final double halfOpenSuccessRate;
    //恢复时间
    private final long retryTimePeriod;
    //上次失败时间
    private long lastFailureTime = 0;

    public CircuitBreaker(int failureThreshold, double halfOpenSuccessRate, long retryTimePeriod){
        this.failureThreshold = failureThreshold;
        this.halfOpenSuccessRate = halfOpenSuccessRate;
        this.retryTimePeriod = retryTimePeriod;
    }

    /*
     * @param :
      * @return boolean
     * @author 10091
     * @description 查看当前熔断器是否允许请求通过
     * @date 2024/9/6 0:41
     */
    public synchronized boolean allowRequest(){
        long currentTime = System.currentTimeMillis();
        switch (state){
            case OPEN:
                if(currentTime - lastFailureTime > retryTimePeriod){
                    state = CircuitBreakerState.HALF_OPEN;
                    return true;
                }
                return false;
            case HALF_OPEN:
                requestCount.incrementAndGet();
                return true;
            case CLOSED:
            default:
                return true;
        }
    }

    /*
     * @param :
      * @return void
     * @author 10091
     * @description 记录成功
     * @date 2024/9/6 0:47
     */
    public synchronized void recordSuccess(){
        if(state == CircuitBreakerState.HALF_OPEN){
            successCount.incrementAndGet();
            if(successCount.get() >= halfOpenSuccessRate * requestCount.get()){
                state = CircuitBreakerState.CLOSED;
                resetCounts();
            }
        }
        else {
            resetCounts();
        }
    }

    /*
     * @param :
      * @return void
     * @author 10091
     * @description 记录失败
     * @date 2024/9/6 0:47
     */
    public synchronized void recordFailure(){
        failureCount.incrementAndGet();
        lastFailureTime = System.currentTimeMillis();
        if(state == CircuitBreakerState.HALF_OPEN){
            state = CircuitBreakerState.OPEN;
            lastFailureTime = System.currentTimeMillis();
        }
        else if(failureCount.get() >= failureThreshold){
            state = CircuitBreakerState.OPEN;
        }
    }

    //重置次数
    private void resetCounts() {
        failureCount.set(0);
        successCount.set(0);
        requestCount.set(0);
    }

    enum CircuitBreakerState {
        //关闭，开启，半开启
        CLOSED, OPEN, HALF_OPEN
    }
}
